Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
matrix.c
Go to the documentation of this file.
1 // Copyright (c) 2014, 2015, 2016, NXP Semiconductors N.V.,
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name of NXP Semiconductors N.V. nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL NXP SEMICONDUCTORS N.V. BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 // This file contains matrix manipulation functions.
26 
27 /*! \file matrix.c
28  \brief Matrix manipulation functions
29 
30  Contains functions for basic manipulation of 3x3 matrices
31 */
32 
33 #include "stdio.h"
34 #include "math.h"
35 #include "stdlib.h"
36 #include "time.h"
37 
38 #include "sensor_fusion.h"
39 #include "matrix.h"
40 
41 // compile time constants that are private to this file
42 #define CORRUPTMATRIX 0.001F // column vector modulus limit for rotation matrix
43 
44 // function sets the 3x3 matrix A to the identity matrix
45 void f3x3matrixAeqI(float A[][3])
46 {
47  float *pAij; // pointer to A[i][j]
48  int8 i,
49  j; // loop counters
50  for (i = 0; i < 3; i++)
51  {
52  // set pAij to &A[i][j=0]
53  pAij = A[i];
54  for (j = 0; j < 3; j++)
55  {
56  *(pAij++) = 0.0F;
57  }
58 
59  A[i][i] = 1.0F;
60  }
61 
62  return;
63 }
64 
65 // function sets 3x3 matrix A to 3x3 matrix B
66 void f3x3matrixAeqB(float A[][3], float B[][3])
67 {
68  float *pAij; // pointer to A[i][j]
69  float *pBij; // pointer to B[i][j]
70  int8 i,
71  j; // loop counters
72  for (i = 0; i < 3; i++)
73  {
74  // set pAij to &A[i][j=0] and pBij to &B[i][j=0]
75  pAij = A[i];
76  pBij = B[i];
77  for (j = 0; j < 3; j++)
78  {
79  *(pAij++) = *(pBij++);
80  }
81  }
82 
83  return;
84 }
85 
86 // function sets the matrix A to the identity matrix
87 void fmatrixAeqI(float *A[], int16 rc)
88 {
89  // rc = rows and columns in A
90  float *pAij; // pointer to A[i][j]
91  int8 i,
92  j; // loop counters
93  for (i = 0; i < rc; i++)
94  {
95  // set pAij to &A[i][j=0]
96  pAij = A[i];
97  for (j = 0; j < rc; j++)
98  {
99  *(pAij++) = 0.0F;
100  }
101 
102  A[i][i] = 1.0F;
103  }
104 
105  return;
106 }
107 
108 // function sets every entry in the 3x3 matrix A to a constant scalar
109 void f3x3matrixAeqScalar(float A[][3], float Scalar)
110 {
111  float *pAij; // pointer to A[i][j]
112  int8 i,
113  j; // counters
114  for (i = 0; i < 3; i++)
115  {
116  // set pAij to &A[i][j=0]
117  pAij = A[i];
118  for (j = 0; j < 3; j++)
119  {
120  *(pAij++) = Scalar;
121  }
122  }
123 
124  return;
125 }
126 
127 // function multiplies all elements of 3x3 matrix A by the specified scalar
128 void f3x3matrixAeqAxScalar(float A[][3], float Scalar)
129 {
130  float *pAij; // pointer to A[i][j]
131  int8 i,
132  j; // loop counters
133  for (i = 0; i < 3; i++)
134  {
135  // set pAij to &A[i][j=0]
136  pAij = A[i];
137  for (j = 0; j < 3; j++)
138  {
139  *(pAij++) *= Scalar;
140  }
141  }
142 
143  return;
144 }
145 
146 // function negates all elements of 3x3 matrix A
147 void f3x3matrixAeqMinusA(float A[][3])
148 {
149  float *pAij; // pointer to A[i][j]
150  int8 i,
151  j; // loop counters
152  for (i = 0; i < 3; i++)
153  {
154  // set pAij to &A[i][j=0]
155  pAij = A[i];
156  for (j = 0; j < 3; j++)
157  {
158  *pAij = -*pAij;
159  pAij++;
160  }
161  }
162 
163  return;
164 }
165 
166 // function directly calculates the symmetric inverse of a symmetric 3x3 matrix
167 // only the on and above diagonal terms in B are used and need to be specified
168 void f3x3matrixAeqInvSymB(float A[][3], float B[][3])
169 {
170  float fB11B22mB12B12; // B[1][1] * B[2][2] - B[1][2] * B[1][2]
171  float fB12B02mB01B22; // B[1][2] * B[0][2] - B[0][1] * B[2][2]
172  float fB01B12mB11B02; // B[0][1] * B[1][2] - B[1][1] * B[0][2]
173  float ftmp; // determinant and then reciprocal
174 
175  // calculate useful products
176  fB11B22mB12B12 = B[1][1] * B[2][2] - B[1][2] * B[1][2];
177  fB12B02mB01B22 = B[1][2] * B[0][2] - B[0][1] * B[2][2];
178  fB01B12mB11B02 = B[0][1] * B[1][2] - B[1][1] * B[0][2];
179 
180  // set ftmp to the determinant of the input matrix B
181  ftmp = B[0][0] *
182  fB11B22mB12B12 +
183  B[0][1] *
184  fB12B02mB01B22 +
185  B[0][2] *
186  fB01B12mB11B02;
187 
188  // set A to the inverse of B for any determinant except zero
189  if (ftmp != 0.0F)
190  {
191  ftmp = 1.0F / ftmp;
192  A[0][0] = fB11B22mB12B12 * ftmp;
193  A[1][0] = A[0][1] = fB12B02mB01B22 * ftmp;
194  A[2][0] = A[0][2] = fB01B12mB11B02 * ftmp;
195  A[1][1] = (B[0][0] * B[2][2] - B[0][2] * B[0][2]) * ftmp;
196  A[2][1] = A[1][2] = (B[0][2] * B[0][1] - B[0][0] * B[1][2]) * ftmp;
197  A[2][2] = (B[0][0] * B[1][1] - B[0][1] * B[0][1]) * ftmp;
198  }
199  else
200  {
201  // provide the identity matrix if the determinant is zero
202  f3x3matrixAeqI(A);
203  }
204 
205  return;
206 }
207 
208 // function calculates the determinant of a 3x3 matrix
209 float f3x3matrixDetA(float A[][3])
210 {
211  return
212  (
213  A[CHX][CHX] *
214  (
215  A[CHY][CHY] *
216  A[CHZ][CHZ] -
217  A[CHY][CHZ] *
218  A[CHZ][CHY]
219  ) +
220  A[CHX][CHY] *
221  (A[CHY][CHZ] * A[CHZ][CHX] - A[CHY][CHX] * A[CHZ][CHZ]) +
222  A[CHX][CHZ] *
223  (A[CHY][CHX] * A[CHZ][CHY] - A[CHY][CHY] * A[CHZ][CHX])
224  );
225 }
226 
227 // function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1]
228 // stored in the top left of a 10x10 array A[10][10]
229 // A[][] is changed on output.
230 // eigval[0..n-1] returns the eigenvalues of A[][].
231 // eigvec[0..n-1][0..n-1] returns the normalized eigenvectors of A[][]
232 // the eigenvectors are not sorted by value
233 // n can vary up to and including 10 but the matrices A and eigvec must have 10 columns.
234 void fEigenCompute10(float A[][10], float eigval[], float eigvec[][10], int8 n)
235 {
236  // maximum number of iterations to achieve convergence: in practice 6 is typical
237 #define NITERATIONS 15
238  // various trig functions of the jacobi rotation angle phi
239  float cot2phi,
240  tanhalfphi,
241  tanphi,
242  sinphi,
243  cosphi;
244 
245  // scratch variable to prevent over-writing during rotations
246  float ftmp;
247 
248  // residue from remaining non-zero above diagonal terms
249  float residue;
250 
251  // matrix row and column indices
252  int8 i,
253  j;
254 
255  // general loop counter
256  int8 k;
257 
258  // timeout ctr for number of passes of the algorithm
259  int8 ctr;
260 
261  // initialize eigenvectors matrix and eigenvalues array
262  for (i = 0; i < n; i++)
263  {
264  // loop over all columns
265  for (j = 0; j < n; j++)
266  {
267  // set on diagonal and off-diagonal elements to zero
268  eigvec[i][j] = 0.0F;
269  }
270 
271  // correct the diagonal elements to 1.0
272  eigvec[i][i] = 1.0F;
273 
274  // initialize the array of eigenvalues to the diagonal elements of A
275  eigval[i] = A[i][i];
276  }
277 
278  // initialize the counter and loop until converged or NITERATIONS reached
279  ctr = 0;
280  do
281  {
282  // compute the absolute value of the above diagonal elements as exit criterion
283  residue = 0.0F;
284 
285  // loop over rows excluding last row
286  for (i = 0; i < n - 1; i++)
287  {
288  // loop over above diagonal columns
289  for (j = i + 1; j < n; j++)
290  {
291  // accumulate the residual off diagonal terms which are being driven to zero
292  residue += fabsf(A[i][j]);
293  }
294  }
295 
296  // check if we still have work to do
297  if (residue > 0.0F)
298  {
299  // loop over all rows with the exception of the last row (since only rotating above diagonal elements)
300  for (i = 0; i < n - 1; i++)
301  {
302  // loop over columns j (where j is always greater than i since above diagonal)
303  for (j = i + 1; j < n; j++)
304  {
305  // only continue with this element if the element is non-zero
306  if (fabsf(A[i][j]) > 0.0F)
307  {
308  // calculate cot(2*phi) where phi is the Jacobi rotation angle
309  cot2phi = 0.5F * (eigval[j] - eigval[i]) / (A[i][j]);
310 
311  // calculate tan(phi) correcting sign to ensure the smaller solution is used
312  tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
313  if (cot2phi < 0.0F)
314  {
315  tanphi = -tanphi;
316  }
317 
318  // calculate the sine and cosine of the Jacobi rotation angle phi
319  cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
320  sinphi = tanphi * cosphi;
321 
322  // calculate tan(phi/2)
323  tanhalfphi = sinphi / (1.0F + cosphi);
324 
325  // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
326  ftmp = tanphi * A[i][j];
327 
328  // apply the jacobi rotation to diagonal elements [i][i] and [j][j] stored in the eigenvalue array
329  // eigval[i] = eigval[i] - tan(phi) * A[i][j]
330  eigval[i] -= ftmp;
331 
332  // eigval[j] = eigval[j] + tan(phi) * A[i][j]
333  eigval[j] += ftmp;
334 
335  // by definition, applying the jacobi rotation on element i, j results in 0.0
336  A[i][j] = 0.0F;
337 
338  // apply the jacobi rotation to all elements of the eigenvector matrix
339  for (k = 0; k < n; k++)
340  {
341  // store eigvec[k][i]
342  ftmp = eigvec[k][i];
343 
344  // eigvec[k][i] = eigvec[k][i] - sin(phi) * (eigvec[k][j] + tan(phi/2) * eigvec[k][i])
345  eigvec[k][i] = ftmp - sinphi * (eigvec[k][j] + tanhalfphi * ftmp);
346 
347  // eigvec[k][j] = eigvec[k][j] + sin(phi) * (eigvec[k][i] - tan(phi/2) * eigvec[k][j])
348  eigvec[k][j] = eigvec[k][j] + sinphi * (ftmp - tanhalfphi * eigvec[k][j]);
349  }
350 
351  // apply the jacobi rotation only to those elements of matrix m that can change
352  for (k = 0; k <= i - 1; k++)
353  {
354  // store A[k][i]
355  ftmp = A[k][i];
356 
357  // A[k][i] = A[k][i] - sin(phi) * (A[k][j] + tan(phi/2) * A[k][i])
358  A[k][i] = ftmp - sinphi * (A[k][j] + tanhalfphi * ftmp);
359 
360  // A[k][j] = A[k][j] + sin(phi) * (A[k][i] - tan(phi/2) * A[k][j])
361  A[k][j] = A[k][j] + sinphi * (ftmp - tanhalfphi * A[k][j]);
362  }
363 
364  for (k = i + 1; k <= j - 1; k++)
365  {
366  // store A[i][k]
367  ftmp = A[i][k];
368 
369  // A[i][k] = A[i][k] - sin(phi) * (A[k][j] + tan(phi/2) * A[i][k])
370  A[i][k] = ftmp - sinphi * (A[k][j] + tanhalfphi * ftmp);
371 
372  // A[k][j] = A[k][j] + sin(phi) * (A[i][k] - tan(phi/2) * A[k][j])
373  A[k][j] = A[k][j] + sinphi * (ftmp - tanhalfphi * A[k][j]);
374  }
375 
376  for (k = j + 1; k < n; k++)
377  {
378  // store A[i][k]
379  ftmp = A[i][k];
380 
381  // A[i][k] = A[i][k] - sin(phi) * (A[j][k] + tan(phi/2) * A[i][k])
382  A[i][k] = ftmp - sinphi * (A[j][k] + tanhalfphi * ftmp);
383 
384  // A[j][k] = A[j][k] + sin(phi) * (A[i][k] - tan(phi/2) * A[j][k])
385  A[j][k] = A[j][k] + sinphi * (ftmp - tanhalfphi * A[j][k]);
386  }
387  } // end of test for matrix element A[i][j] non-zero
388  } // end of loop over columns j
389  } // end of loop over rows i
390  } // end of test for non-zero value of residue
391  } while ((residue > 0.0F) && (ctr++ < NITERATIONS));
392 
393  // end of main loop
394  return;
395 }
396 
397 // function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1]
398 // stored in the top left of a 4x4 array A[4][4]
399 // A[][] is changed on output.
400 // eigval[0..n-1] returns the eigenvalues of A[][].
401 // eigvec[0..n-1][0..n-1] returns the normalized eigenvectors of A[][]
402 // the eigenvectors are not sorted by value
403 // n can vary up to and including 4 but the matrices A and eigvec must have 4 columns.
404 // this function is identical to eigencompute10 except for the workaround for 4x4 matrices since C cannot
405 
406 // handle functions accepting matrices with variable numbers of columns.
407 void fEigenCompute4(float A[][4], float eigval[], float eigvec[][4], int8 n)
408 {
409  // maximum number of iterations to achieve convergence: in practice 6 is typical
410 #define NITERATIONS 15
411  // various trig functions of the jacobi rotation angle phi
412  float cot2phi,
413  tanhalfphi,
414  tanphi,
415  sinphi,
416  cosphi;
417 
418  // scratch variable to prevent over-writing during rotations
419  float ftmp;
420 
421  // residue from remaining non-zero above diagonal terms
422  float residue;
423 
424  // matrix row and column indices
425  int8 ir,
426  ic;
427 
428  // general loop counter
429  int8 j;
430 
431  // timeout ctr for number of passes of the algorithm
432  int8 ctr;
433 
434  // initialize eigenvectors matrix and eigenvalues array
435  for (ir = 0; ir < n; ir++)
436  {
437  // loop over all columns
438  for (ic = 0; ic < n; ic++)
439  {
440  // set on diagonal and off-diagonal elements to zero
441  eigvec[ir][ic] = 0.0F;
442  }
443 
444  // correct the diagonal elements to 1.0
445  eigvec[ir][ir] = 1.0F;
446 
447  // initialize the array of eigenvalues to the diagonal elements of m
448  eigval[ir] = A[ir][ir];
449  }
450 
451  // initialize the counter and loop until converged or NITERATIONS reached
452  ctr = 0;
453  do
454  {
455  // compute the absolute value of the above diagonal elements as exit criterion
456  residue = 0.0F;
457 
458  // loop over rows excluding last row
459  for (ir = 0; ir < n - 1; ir++)
460  {
461  // loop over above diagonal columns
462  for (ic = ir + 1; ic < n; ic++)
463  {
464  // accumulate the residual off diagonal terms which are being driven to zero
465  residue += fabsf(A[ir][ic]);
466  }
467  }
468 
469  // check if we still have work to do
470  if (residue > 0.0F)
471  {
472  // loop over all rows with the exception of the last row (since only rotating above diagonal elements)
473  for (ir = 0; ir < n - 1; ir++)
474  {
475  // loop over columns ic (where ic is always greater than ir since above diagonal)
476  for (ic = ir + 1; ic < n; ic++)
477  {
478  // only continue with this element if the element is non-zero
479  if (fabsf(A[ir][ic]) > 0.0F)
480  {
481  // calculate cot(2*phi) where phi is the Jacobi rotation angle
482  cot2phi = 0.5F *
483  (eigval[ic] - eigval[ir]) /
484  (A[ir][ic]);
485 
486  // calculate tan(phi) correcting sign to ensure the smaller solution is used
487  tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
488  if (cot2phi < 0.0F)
489  {
490  tanphi = -tanphi;
491  }
492 
493  // calculate the sine and cosine of the Jacobi rotation angle phi
494  cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
495  sinphi = tanphi * cosphi;
496 
497  // calculate tan(phi/2)
498  tanhalfphi = sinphi / (1.0F + cosphi);
499 
500  // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
501  ftmp = tanphi * A[ir][ic];
502 
503  // apply the jacobi rotation to diagonal elements [ir][ir] and [ic][ic] stored in the eigenvalue array
504  // eigval[ir] = eigval[ir] - tan(phi) * A[ir][ic]
505  eigval[ir] -= ftmp;
506 
507  // eigval[ic] = eigval[ic] + tan(phi) * A[ir][ic]
508  eigval[ic] += ftmp;
509 
510  // by definition, applying the jacobi rotation on element ir, ic results in 0.0
511  A[ir][ic] = 0.0F;
512 
513  // apply the jacobi rotation to all elements of the eigenvector matrix
514  for (j = 0; j < n; j++)
515  {
516  // store eigvec[j][ir]
517  ftmp = eigvec[j][ir];
518 
519  // eigvec[j][ir] = eigvec[j][ir] - sin(phi) * (eigvec[j][ic] + tan(phi/2) * eigvec[j][ir])
520  eigvec[j][ir] = ftmp - sinphi * (eigvec[j][ic] + tanhalfphi * ftmp);
521 
522  // eigvec[j][ic] = eigvec[j][ic] + sin(phi) * (eigvec[j][ir] - tan(phi/2) * eigvec[j][ic])
523  eigvec[j][ic] = eigvec[j][ic] + sinphi * (ftmp - tanhalfphi * eigvec[j][ic]);
524  }
525 
526  // apply the jacobi rotation only to those elements of matrix m that can change
527  for (j = 0; j <= ir - 1; j++)
528  {
529  // store A[j][ir]
530  ftmp = A[j][ir];
531 
532  // A[j][ir] = A[j][ir] - sin(phi) * (A[j][ic] + tan(phi/2) * A[j][ir])
533  A[j][ir] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
534 
535  // A[j][ic] = A[j][ic] + sin(phi) * (A[j][ir] - tan(phi/2) * A[j][ic])
536  A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
537  }
538 
539  for (j = ir + 1; j <= ic - 1; j++)
540  {
541  // store A[ir][j]
542  ftmp = A[ir][j];
543 
544  // A[ir][j] = A[ir][j] - sin(phi) * (A[j][ic] + tan(phi/2) * A[ir][j])
545  A[ir][j] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
546 
547  // A[j][ic] = A[j][ic] + sin(phi) * (A[ir][j] - tan(phi/2) * A[j][ic])
548  A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
549  }
550 
551  for (j = ic + 1; j < n; j++)
552  {
553  // store A[ir][j]
554  ftmp = A[ir][j];
555 
556  // A[ir][j] = A[ir][j] - sin(phi) * (A[ic][j] + tan(phi/2) * A[ir][j])
557  A[ir][j] = ftmp - sinphi * (A[ic][j] + tanhalfphi * ftmp);
558 
559  // A[ic][j] = A[ic][j] + sin(phi) * (A[ir][j] - tan(phi/2) * A[ic][j])
560  A[ic][j] = A[ic][j] + sinphi * (ftmp - tanhalfphi * A[ic][j]);
561  }
562  } // end of test for matrix element already zero
563  } // end of loop over columns
564  } // end of loop over rows
565  } // end of test for non-zero residue
566  } while ((residue > 0.0F) && (ctr++ < NITERATIONS));
567 
568  // end of main loop
569  return;
570 }
571 
572 void fComputeEigSlice(float fmatA[10][10], float fmatB[10][10], float fvecA[10],
573  int8 i, int8 j, int8 iMatrixSize)
574 {
575  float cot2phi; // cotangent of half jacobi rotation angle
576  float tanhalfphi; // tangent of half jacobi rotation angle
577  float tanphi; // tangent of jacobi rotation angle
578  float sinphi; // sine of jacobi rotation angle
579  float cosphi; // cosine of jacobi rotation angle
580  float ftmp; // scratch
581  int8 k; // loop counter
582 
583  // calculate cot(2*phi) where phi is the Jacobi rotation angle
584  cot2phi = 0.5F * (fvecA[j] - fvecA[i]) / (fmatA[i][j]);
585 
586  // calculate tan(phi) correcting sign to ensure the smaller solution is used
587  tanphi = 1.0F / (fabsf(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
588  if (cot2phi < 0.0F) tanphi = -tanphi;
589 
590  // calculate the sine and cosine of the Jacobi rotation angle phi
591  cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
592  sinphi = tanphi * cosphi;
593 
594  // calculate tan(phi/2)
595  tanhalfphi = sinphi / (1.0F + cosphi);
596 
597  // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
598  ftmp = tanphi * fmatA[i][j];
599 
600  // apply the jacobi rotation to diagonal elements [i][i] and [j][j] stored in the eigenvalue array
601  // fvecA[i] = fvecA[i] - tan(phi) * fmatA[i][j]
602  fvecA[i] -= ftmp;
603 
604  // fvecA[j] = fvecA[j] + tan(phi) * fmatA[i][j]
605  fvecA[j] += ftmp;
606 
607  // by definition, applying the jacobi rotation on element i, j results in 0.0
608  fmatA[i][j] = 0.0F;
609 
610  // apply the jacobi rotation to all elements of the eigenvector matrix
611  for (k = 0; k < iMatrixSize; k++)
612  {
613  // store fmatB[k][i]
614  ftmp = fmatB[k][i];
615 
616  // fmatB[k][i] = fmatB[k][i] - sin(phi) * (fmatB[k][j] + tan(phi/2) * fmatB[k][i])
617  fmatB[k][i] = ftmp - sinphi * (fmatB[k][j] + tanhalfphi * ftmp);
618 
619  // fmatB[k][j] = fmatB[k][j] + sin(phi) * (fmatB[k][i] - tan(phi/2) * fmatB[k][j])
620  fmatB[k][j] = fmatB[k][j] + sinphi * (ftmp - tanhalfphi * fmatB[k][j]);
621  }
622 
623  // apply the jacobi rotation only to those elements of matrix that can change
624  for (k = 0; k <= i - 1; k++)
625  {
626  // store fmatA[k][i]
627  ftmp = fmatA[k][i];
628 
629  // fmatA[k][i] = fmatA[k][i] - sin(phi) * (fmatA[k][j] + tan(phi/2) * fmatA[k][i])
630  fmatA[k][i] = ftmp - sinphi * (fmatA[k][j] + tanhalfphi * ftmp);
631 
632  // fmatA[k][j] = fmatA[k][j] + sin(phi) * (fmatA[k][i] - tan(phi/2) * fmatA[k][j])
633  fmatA[k][j] = fmatA[k][j] + sinphi * (ftmp - tanhalfphi * fmatA[k][j]);
634  }
635 
636  for (k = i + 1; k <= j - 1; k++)
637  {
638  // store fmatA[i][k]
639  ftmp = fmatA[i][k];
640 
641  // fmatA[i][k] = fmatA[i][k] - sin(phi) * (fmatA[k][j] + tan(phi/2) * fmatA[i][k])
642  fmatA[i][k] = ftmp - sinphi * (fmatA[k][j] + tanhalfphi * ftmp);
643 
644  // fmatA[k][j] = fmatA[k][j] + sin(phi) * (fmatA[i][k] - tan(phi/2) * fmatA[k][j])
645  fmatA[k][j] = fmatA[k][j] + sinphi * (ftmp - tanhalfphi * fmatA[k][j]);
646  }
647 
648  for (k = j + 1; k < iMatrixSize; k++)
649  {
650  // store fmatA[i][k]
651  ftmp = fmatA[i][k];
652 
653  // fmatA[i][k] = fmatA[i][k] - sin(phi) * (fmatA[j][k] + tan(phi/2) * fmatA[i][k])
654  fmatA[i][k] = ftmp - sinphi * (fmatA[j][k] + tanhalfphi * ftmp);
655 
656  // fmatA[j][k] = fmatA[j][k] + sin(phi) * (fmatA[i][k] - tan(phi/2) * fmatA[j][k])
657  fmatA[j][k] = fmatA[j][k] + sinphi * (ftmp - tanhalfphi * fmatA[j][k]);
658  }
659 
660  return;
661 }
662 
663 // function uses Gauss-Jordan elimination to compute the inverse of matrix A in situ
664 
665 // on exit, A is replaced with its inverse
666 void fmatrixAeqInvA(float *A[], int8 iColInd[], int8 iRowInd[], int8 iPivot[],
667  int8 isize, int8 *pierror)
668 {
669  float largest; // largest element used for pivoting
670  float scaling; // scaling factor in pivoting
671  float recippiv; // reciprocal of pivot element
672  float ftmp; // temporary variable used in swaps
673  int8 i,
674  j,
675  k,
676  l,
677  m; // index counters
678  int8 iPivotRow,
679  iPivotCol; // row and column of pivot element
680 
681  // to avoid compiler warnings
682  iPivotRow = iPivotCol = 0;
683 
684  // default to successful inversion
685  *pierror = false;
686 
687  // initialize the pivot array to 0
688  for (j = 0; j < isize; j++)
689  {
690  iPivot[j] = 0;
691  }
692 
693  // main loop i over the dimensions of the square matrix A
694  for (i = 0; i < isize; i++)
695  {
696  // zero the largest element found for pivoting
697  largest = 0.0F;
698 
699  // loop over candidate rows j
700  for (j = 0; j < isize; j++)
701  {
702  // check if row j has been previously pivoted
703  if (iPivot[j] != 1)
704  {
705  // loop over candidate columns k
706  for (k = 0; k < isize; k++)
707  {
708  // check if column k has previously been pivoted
709  if (iPivot[k] == 0)
710  {
711  // check if the pivot element is the largest found so far
712  if (fabsf(A[j][k]) >= largest)
713  {
714  // and store this location as the current best candidate for pivoting
715  iPivotRow = j;
716  iPivotCol = k;
717  largest = (float) fabsf(A[iPivotRow][iPivotCol]);
718  }
719  }
720  else if (iPivot[k] > 1)
721  {
722  // zero determinant situation: exit with identity matrix and set error flag
723  fmatrixAeqI(A, isize);
724  *pierror = true;
725  return;
726  }
727  }
728  }
729  }
730 
731  // increment the entry in iPivot to denote it has been selected for pivoting
732  iPivot[iPivotCol]++;
733 
734  // check the pivot rows iPivotRow and iPivotCol are not the same before swapping
735  if (iPivotRow != iPivotCol)
736  {
737  // loop over columns l
738  for (l = 0; l < isize; l++)
739  {
740  // and swap all elements of rows iPivotRow and iPivotCol
741  ftmp = A[iPivotRow][l];
742  A[iPivotRow][l] = A[iPivotCol][l];
743  A[iPivotCol][l] = ftmp;
744  }
745  }
746 
747  // record that on the i-th iteration rows iPivotRow and iPivotCol were swapped
748  iRowInd[i] = iPivotRow;
749  iColInd[i] = iPivotCol;
750 
751  // check for zero on-diagonal element (singular matrix) and return with identity matrix if detected
752  if (A[iPivotCol][iPivotCol] == 0.0F)
753  {
754  // zero determinant situation: exit with identity matrix and set error flag
755  fmatrixAeqI(A, isize);
756  *pierror = true;
757  return;
758  }
759 
760  // calculate the reciprocal of the pivot element knowing it's non-zero
761  recippiv = 1.0F / A[iPivotCol][iPivotCol];
762 
763  // by definition, the diagonal element normalizes to 1
764  A[iPivotCol][iPivotCol] = 1.0F;
765 
766  // multiply all of row iPivotCol by the reciprocal of the pivot element including the diagonal element
767  // the diagonal element A[iPivotCol][iPivotCol] now has value equal to the reciprocal of its previous value
768  for (l = 0; l < isize; l++)
769  {
770  if (A[iPivotCol][l] != 0.0F) A[iPivotCol][l] *= recippiv;
771  }
772 
773  // loop over all rows m of A
774  for (m = 0; m < isize; m++)
775  {
776  if (m != iPivotCol)
777  {
778  // scaling factor for this row m is in column iPivotCol
779  scaling = A[m][iPivotCol];
780 
781  // zero this element
782  A[m][iPivotCol] = 0.0F;
783 
784  // loop over all columns l of A and perform elimination
785  for (l = 0; l < isize; l++)
786  {
787  if ((A[iPivotCol][l] != 0.0F) && (scaling != 0.0F))
788  A[m][l] -= A[iPivotCol][l] * scaling;
789  }
790  }
791  }
792  } // end of loop i over the matrix dimensions
793 
794  // finally, loop in inverse order to apply the missing column swaps
795  for (l = isize - 1; l >= 0; l--)
796  {
797  // set i and j to the two columns to be swapped
798  i = iRowInd[l];
799  j = iColInd[l];
800 
801  // check that the two columns i and j to be swapped are not the same
802  if (i != j)
803  {
804  // loop over all rows k to swap columns i and j of A
805  for (k = 0; k < isize; k++)
806  {
807  ftmp = A[k][i];
808  A[k][i] = A[k][j];
809  A[k][j] = ftmp;
810  }
811  }
812  }
813 
814  return;
815 }
816 
817 // function rotates 3x1 vector u onto 3x1 vector using 3x3 rotation matrix fR.
818 
819 // the rotation is applied in the inverse direction if itranpose is true
820 void fveqRu(float fv[], float fR[][3], float fu[], int8 itranspose)
821 {
822  if (!itranspose)
823  {
824  // normal, non-transposed rotation
825  fv[CHX] = fR[CHX][CHX] *
826  fu[CHX] +
827  fR[CHX][CHY] *
828  fu[CHY] +
829  fR[CHX][CHZ] *
830  fu[CHZ];
831  fv[CHY] = fR[CHY][CHX] *
832  fu[CHX] +
833  fR[CHY][CHY] *
834  fu[CHY] +
835  fR[CHY][CHZ] *
836  fu[CHZ];
837  fv[CHZ] = fR[CHZ][CHX] *
838  fu[CHX] +
839  fR[CHZ][CHY] *
840  fu[CHY] +
841  fR[CHZ][CHZ] *
842  fu[CHZ];
843  }
844  else
845  {
846  // transposed (inverse rotation)
847  fv[CHX] = fR[CHX][CHX] *
848  fu[CHX] +
849  fR[CHY][CHX] *
850  fu[CHY] +
851  fR[CHZ][CHX] *
852  fu[CHZ];
853  fv[CHY] = fR[CHX][CHY] *
854  fu[CHX] +
855  fR[CHY][CHY] *
856  fu[CHY] +
857  fR[CHZ][CHY] *
858  fu[CHZ];
859  fv[CHZ] = fR[CHX][CHZ] *
860  fu[CHX] +
861  fR[CHY][CHZ] *
862  fu[CHY] +
863  fR[CHZ][CHZ] *
864  fu[CHZ];
865  }
866 
867  return;
868 }
869 
870 // function multiplies the 3x1 vector V by a 3x3 matrix A
871 void fVeq3x3AxV(float V[3], float A[][3])
872 {
873  float ftmp[3]; // scratch vector
874 
875  // set ftmp = V
876  ftmp[CHX] = V[CHX];
877  ftmp[CHY] = V[CHY];
878  ftmp[CHZ] = V[CHZ];
879 
880  // set V = A * ftmp = A * V
881  V[CHX] = A[CHX][CHX] *
882  ftmp[CHX] +
883  A[CHX][CHY] *
884  ftmp[CHY] +
885  A[CHX][CHZ] *
886  ftmp[CHZ];
887  V[CHY] = A[CHY][CHX] *
888  ftmp[CHX] +
889  A[CHY][CHY] *
890  ftmp[CHY] +
891  A[CHY][CHZ] *
892  ftmp[CHZ];
893  V[CHZ] = A[CHZ][CHX] *
894  ftmp[CHX] +
895  A[CHZ][CHY] *
896  ftmp[CHY] +
897  A[CHZ][CHZ] *
898  ftmp[CHZ];
899 
900  return;
901 }
void fmatrixAeqInvA(float *A[], int8 iColInd[], int8 iRowInd[], int8 iPivot[], int8 isize, int8 *pierror)
function uses Gauss-Jordan elimination to compute the inverse of matrix A in situ on exit...
Definition: matrix.c:666
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
void f3x3matrixAeqB(float A[][3], float B[][3])
function sets 3x3 matrix A to 3x3 matrix B
Definition: matrix.c:66
void f3x3matrixAeqMinusA(float A[][3])
function negates all elements of 3x3 matrix A
Definition: matrix.c:147
#define B
Definition: status.c:50
void f3x3matrixAeqAxScalar(float A[][3], float Scalar)
function multiplies all elements of 3x3 matrix A by the specified scalar
Definition: matrix.c:128
float f3x3matrixDetA(float A[][3])
function calculates the determinant of a 3x3 matrix
Definition: matrix.c:209
void fmatrixAeqI(float *A[], int16 rc)
function sets the matrix A to the identity matrix
Definition: matrix.c:87
#define NITERATIONS
void fEigenCompute10(float A[][10], float eigval[], float eigvec[][10], int8 n)
function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1] stored in the top left of a 10x10 array A[10][10]
Definition: matrix.c:234
The sensor_fusion.h file implements the top level programming interface.
void fVeq3x3AxV(float V[3], float A[][3])
function multiplies the 3x1 vector V by a 3x3 matrix A
Definition: matrix.c:871
#define CHZ
void f3x3matrixAeqInvSymB(float A[][3], float B[][3])
function directly calculates the symmetric inverse of a symmetric 3x3 matrix only the on and above di...
Definition: matrix.c:168
Matrix manipulation functions.
void fComputeEigSlice(float fmatA[10][10], float fmatB[10][10], float fvecA[10], int8 i, int8 j, int8 iMatrixSize)
Definition: matrix.c:572
void fEigenCompute4(float A[][4], float eigval[], float eigvec[][4], int8 n)
function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1] stored in the top left of a 4x4 array A[4][4] A[][] is changed on output. The eigenvectors are not sorted by value. This function is identical to eigencompute10 except for the workaround for 4x4 matrices since C cannot handle functions accepting matrices with variable numbers of columns.
Definition: matrix.c:407
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void fveqRu(float fv[], float fR[][3], float fu[], int8 itranspose)
function rotates 3x1 vector u onto 3x1 vector using 3x3 rotation matrix fR. the rotation is applied i...
Definition: matrix.c:820
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45
void f3x3matrixAeqScalar(float A[][3], float Scalar)
function sets every entry in the 3x3 matrix A to a constant scalar
Definition: matrix.c:109
int16_t int16
Definition: sensor_fusion.h:56
int8_t int8
Definition: sensor_fusion.h:55